[アップデート] AWS Amplify AI kitが公開! AI 機能を備えた Web アプリを迅速に構築できるようになりました

[アップデート] AWS Amplify AI kitが公開! AI 機能を備えた Web アプリを迅速に構築できるようになりました

リテールアプリ共創部の中野です。

本日、AWS Amplify で AWS Amplify AI kit が一般公開されました!
以下のような Bedrock のモデルを活用した Web アプリを Amplify を使って数行のコードを書くことで簡単に実装できるようになりました。

https://aws.amazon.com/jp/about-aws/whats-new/2024/11/aws-amplify-full-stack-ai-kit-amazon-bedrock/

Amplify の公式 X にも動画付きで解説が公開されています。

https://x.com/AWSAmplify/status/1858922058945597623

これまでも Amplify と Bedrock を連携したアプリケーションは構築すること自体、可能でした。
以下ブログのように Amplify Gen 2 と Bedrock の連携には、AppSync のカスタムリゾルバーを利用する方法か、Amplify Functions(Lambda リゾルバー)を利用する方法で、間接的に Bedrock API を呼び出す方法が提供されていました。

https://dev.classmethod.jp/articles/amplify-invoke-bedrock/

今回のアップデートでは AppSync や Lambda リゾルバーによる Bedrock 連携について特別な専門知識や運用を意識しなくても、Amplify 側でバックエンドのリソースが組み込まれているため、簡単に利用できるようになったことが大きなメリットかなと考えています。

機能の説明

Amplify で AI 機能のバックエンドを構築するには、Amplify のデータスキーマに AI routes を定義する必要があります。
この routes は、Amplify が内包しているバックエンドの AI 機能とやり取りするための API エンドポイントのようなものです。
現在は 2 種類の routes をサポートしています。

  • Conversation
    • ストリーミングのマルチターン API(複数のターンにまたがる自由形式の会話)
    • 会話とメッセージは DynamoDB に自動的に保存されるため、ユーザーは会話を途中から再開可能
  • Generation
    • 単一同期リクエストのレスポンス用 API
    • 例としては、画像の代替テキストの生成、非構造化入力からの構造化データの生成、要約などが可能

たとえば Amplify のリソース定義を以下のように定義できます。
Conversation の routes 設定をおこなっています。
この設定で Amplify がバックエンドの Bedrock とマルチターン API を使って連携ができるようになります。

import { type ClientSchema, a, defineData } from "@aws-amplify/backend";

const schema = a.schema({
  chat: a
    .conversation({
      aiModel: a.ai.model("Claude 3 Haiku"),
      systemPrompt: "あなたは優秀なアシスタントです。",
    })
    .authorization((allow) => allow.owner()),
});

export type Schema = ClientSchema<typeof schema>;

やってみた

完成形

実際に実装してみたソースコードです。
Bedrock の Claude 3 Haiku を利用して、汎用チャットアプリをつくってみます。

https://github.com/drumnistnakano/amplify-ai-kit-react-sample

Bedrock のモデルアクセス許可

Bedrock のモデルを使ってチャットボットつくるため、事前にモデルアクセスを編集して利用できるようにしておきます

スクリーンショット 2024-11-20 10.01.03.png

Backend の構築

Amplify のバックエンドを構築します。
新しく構築するプロジェクト配下で以下のコマンドを実行します。

npm create amplify@latest

次に Amplify Gen 2 ではサンドボックス機能という開発者の確認用の環境をつくれる機能があるため、サンドボックス用のコマンドでバックエンドのリソースを生成しておきます。

npx ampx sandbox

Both the legacy 'AWS_DEFAULT_REGION' and preferred 'AWS_REGION' environment variables detected. Using 'AWS_REGION'

  Amplify Sandbox

  Identifier:   nakano.yoshiyuki
  Stack:        amplify-amplifytest-nakanoyoshiyuki-sandbox--*******:

  To specify a different sandbox identifier, use --identifier


✨  Synthesis time: 0.02s

⚠️ The --hotswap and --hotswap-fallback flags deliberately introduce CloudFormation drift to speed up deployments
⚠️ They should only be used for development - never use them for your production Stacks!

amplify-amplifytest-nakanoyoshiyuki-sandbox-*******: start: Building

--- 省略 ---

Stack ARN:
arn:aws:cloudformation:ap-northeast-1:-*******::stack/amplify-amplifytest-nakanoyoshiyuki-sandbox-*******/01d089a0-*******-*******-*******-******

✨  Total time: 201.37s

[Sandbox] Watching for file changes...
File written: amplify_outputs.json

上記にあるように、ファイルが変更されるたびに、amplify_outputs.json を書き換えてくれます。
React などのローカルサーバーを起動した際に、この amplify_outputs.json を使ってバックエンドと疎通できるようです。
CloudFormation のコンソールをみると、サンドボックス用のネストされたスタックが作成されていました。

スクリーンショット_2024-11-20_12_23_31.png

次に、バックエンドのリソース定義です。

amplify/data/resource.ts
import { type ClientSchema, a, defineData } from "@aws-amplify/backend";

const schema = a.schema({
  chat: a
    .conversation({
      aiModel: a.ai.model("Claude 3 Haiku"),
      systemPrompt: "あなたは優秀なアシスタントです。",
    })
    .authorization((allow) => allow.owner()),
});

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: "iam",
  },
});

Frontend の構築

Amplify のフロントエンドを構築します。
Vite を使って React のフロントエンドをコマンドから生成しました。

https://vite.dev/guide/#scaffolding-your-first-vite-project

npm create vite@latest chat-app -- --template react-ts

Scaffolding project in /Users/nakano.yoshiyuki/Work/amplify-test/chat-app...

Done. Now run:

  cd chat-app
  npm install
  npm run dev

モノレポ構成にするため、npm workspaces を使ってプロジェクトのルートから chat-app のスクリプトを呼び出せるようにしておきます。

package.json
{
  "name": "amplify-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "workspaces":[
    "chat-app"
  ],
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@aws-amplify/backend": "^1.8.0",
    "@aws-amplify/backend-cli": "^1.4.2",
    "aws-cdk": "^2.167.2",
    "aws-cdk-lib": "^2.167.2",
    "constructs": "^10.4.2",
    "esbuild": "^0.24.0",
    "tsx": "^4.19.2",
    "typescript": "^5.6.3"
  },
  "dependencies": {
    "@aws-amplify/ui-react": "^6.6.0",
    "@aws-amplify/ui-react-ai": "^1.0.0",
    "aws-amplify": "^6.8.2"
  }
}

次に、Amplify を利用したフロントエンドで必要なライブラリを追加しておきます。

npm add aws-amplify @aws-amplify/ui-react @aws-amplify/ui-react-ai

added 59 packages, and audited 1512 packages in 11s

136 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

フロントエンドからサンドボックスで構築したバックエンドに接続するための設定を追加します。
具体的には、Amplify.configure()の引数に amplify_outputs.json を渡します。

chat-app/src/main.tsx
import React, { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { Amplify } from "aws-amplify";
import "@aws-amplify/ui-react/styles.css";
import outputs from "../../amplify_outputs.json";
import { Authenticator } from "@aws-amplify/ui-react";
import { App } from "./App";

Amplify.configure(outputs);

const rootElement = document.getElementById("root");
if (rootElement) {
  createRoot(rootElement).render(
    <StrictMode>
      <Authenticator>
        <App />
      </Authenticator>
    </StrictMode>
  );
}

チャット形式で会話できるように Amplify が提供してくれている AIConversation コンポーネントと useAIConversation フックを利用します。
AIConversation は、以下のドキュメントにあるように、LLM への送信と UI へのレンダリングをラップして提供してくれるコンポーネントのようです。

https://docs.amplify.aws/react/ai/conversation/response-components/#how-it-works

The AIConversation component takes the response components and turns them into tool configurations to send to the LLM. The tool configurations get sent when a user message is sent to the backend, then the backend Lambda merges the tools coming from the client and any schema tools. The LLM sees that it can invoke UI component "tool", with certain input/props. If the LLM chooses to use a response component tool, a message gets sent to the client with the response component name and props. The AIConversation component will then try to render the React component provided with the props the LLM sends.

import React from "react";
import { AIConversation } from "@aws-amplify/ui-react-ai";
import { useAIConversation } from "./client";

export const App = () => {
  const [
    {
      data: { messages },
      isLoading,
    },
    handleSendMessage,
  ] = useAIConversation("chat");

  return (
    <AIConversation
      messages={messages}
      isLoading={isLoading}
      handleSendMessage={handleSendMessage}
    />
  );
};

React のローカルサーバーを立ち上げます。

npm run dev -w chat-app

  VITE v5.4.11  ready in 468 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show help

http://localhost:5173 にブラウザでアクセスすると認証画面が表示されます。
メールアドレスとパスワードで Sign Up します。

スクリーンショット 2024-11-20 11.52.53.png

チャットの画面がでてきたので、入力ボックスに日本語で質問してみます。
Lambda について聞いてみました。

スクリーンショット 2024-11-20 13.55.20.png

さいごに

AWS Amplify で AWS Amplify AI Kit が一般公開されました!
この機能を使うことで Bedrock と連携するための標準機能が Amplify 側に搭載されました。

routes の設定について細かな設定ができるようでシステムプロンプトや特定の要件でプロンプトを呼び出せる設定などできるようでした。
今回のブログには書ききれませんでしたが、色々試してみたいと思います。

import { a, defineData, type ClientSchema } from "@aws-amplify/backend";

const schema = a.schema({
  // This will add a new conversation route to your Amplify Data backend.
  chat: a
    .conversation({
      aiModel: a.ai.model("Claude 3 Haiku"),
      systemPrompt: "You are a helpful assistant",
    })
    .authorization((allow) => allow.owner()),

  // This adds a new generation route to your Amplify Data backend.
  generateRecipe: a
    .generation({
      aiModel: a.ai.model("Claude 3 Haiku"),
      systemPrompt: "You are a helpful assistant that generates recipes.",
    })
    .arguments({
      description: a.string(),
    })
    .returns(
      a.customType({
        name: a.string(),
        ingredients: a.string().array(),
        instructions: a.string(),
      })
    )
    .authorization((allow) => allow.authenticated()),
});

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: "userPool",
  },
});

公式ブログより

この記事が誰かのお役に立てれば。

参考

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.